/*
 * Copyright 2017 ZZJR All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
// Created on 2017年2月4日
// $Id$

package com.clf.data.redis.core;

import com.alibaba.fastjson.TypeReference;
import com.clf.data.redis.core.json.FastJsonRedisTemplate;
import com.google.common.base.Optional;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * Description: druid connect test
 *
 * @author <a href="mailto:yrh@qtz360.com">yrh</a>
 * @Date Create on 2018年07月27日
 * @since version1.0 Copyright 2018 QTZ All Rights Reserved.
 */
@Component
public class RedisOperatorImpl extends AbstractRedisOperator {
	
	private FastJsonRedisTemplate<String, Object> template;

	@Resource
	public void setFastJsonRedisTemplate(FastJsonRedisTemplate<String, Object> template) {
		this.template = template;
	}

	// ---------------------key/value

	/**
	 * key/value操作，根据key获得value
	 * 
	 * @param key
	 *            String
	 * @return Optional<String> Optional.absent() means null
	 */
	public Optional<String> getImpl(String key) {
		if (!Optional.fromNullable(key).isPresent()) {
			return Optional.absent();
		}
		return (Optional<String>) getOptional(template.opsForValue().get(key, String.class));
	}

	/**
	 * key/value操作，根据key获得value，并转换成指定class
	 * 
	 * @param key
	 * @param clz
	 * @return
	 */
	@Override
	public <T> Optional<T> getImpl(String key, Class<T> clz) {
		if (!Optional.fromNullable(key).isPresent()) {
			return Optional.absent();
		}
		return getOptional((T) template.opsForValue().get(key, clz));
	}

	/**
	 * key/value操作，根据key获得value的列表，并转换成指定class
	 * 
	 * @param key
	 *            String
	 * @param clz
	 *            Reference E List<E>
	 * @return Optional<List<E>> Optional.absent() means null
	 */
	@Override
	public <E> Optional<List<E>> getForListImpl(String key, Class<E> clz) {
		if (!Optional.fromNullable(key).isPresent()) {
			return Optional.absent();
		}
		return getOptional(template.opsForValue().getList(key, clz));
	}

	/**
	 * key/value操作，根据key设置value
	 * 
	 * @param key
	 *            String
	 * @param value
	 *            Object
	 */
	@Override
	public void setImpl(String key, Object value) {
		template.opsForValue().set(key, value);
	}

	/**
	 * key/value操作，根据key设置value,设置过期时间
	 * 
	 * @param key
	 * @param value
	 * @param seconds
	 */
	@Override
	public void setImpl(String key, Object value, long seconds) {
		template.opsForValue().set(key, value, seconds, TimeUnit.SECONDS);
	}

	/**
	 * key/value操作，根据key设置value,设置过期时间
	 * 
	 * @param key
	 * @param value
	 * @param timeout
	 * @param unit
	 */
	@Override
	public void setImpl(String key, Object value, long timeout, TimeUnit unit) {
		template.opsForValue().set(key, value, timeout, unit);
	}
	/**
	 *  key/value操作，根据key设置value,只有redis中key不存在时，才插入值
	 *
	 * @param key
	 *            must not be {@literal null}.
	 * @param value
	 *            must not be {@literal null}.
	 * @return
	 * @see <a href="http://redis.io/commands/setnx">Redis Documentation:
	 *      SETNX</a>
	 */
	@Override
	public Optional<Boolean> setNxImpl(String key, Object value) {
		if (!Optional.fromNullable(key).isPresent()) {
			return Optional.absent();
		}
		return getOptional(template.opsForValue().setIfAbsent(key, value));
	}
	/**
	 *  key/value操作，根据key设置value,只有redis中key不存在时，才插入值，并设置过期时间
	 * 
	 * @param key
	 *            String
	 * @param value
	 *            object
	 * @param seconds
	 *            timeout seconds
	 */
	@Override
	public void setExImpl(String key, Object value, long seconds) {
		template.opsForValue().set(key, value, seconds, TimeUnit.SECONDS);
	}
	/**
	 * key/value操作，根据key设置value,只有redis中key不存在时，才插入值，并设置过期时间
	 * 
	 * @param key
	 *            String
	 * @param value
	 *            object
	 * @param timeout
	 *            timeout
	 * @param unit
	 *            time unit
	 */
	@Override
	public void setExImpl(String key, Object value, long timeout, TimeUnit unit) {
		template.opsForValue().set(key, value, timeout, unit);
	}
	/**
	 * 自增1
	 * 
	 * @param key
	 *            String
	 * @return the incred value
	 */
	@Override
	public Optional<Long> incrImpl(String key) {
		return incrBy(key, 1);
	}
	/**
	 *自增指定值
	 * 
	 * @param key
	 *            String
	 * @param delta
	 *            increment number
	 * @return eht incred value
	 */
	@Override
	public Optional<Long> incrByImpl(String key, final long delta) {
		if (!Optional.fromNullable(key).isPresent()) {
			return Optional.absent();
		}
		return getOptional(template.opsForValue().increment(key, delta));
	}
	/**
	 * 自减指定值
	 * @param key
	 * @param delta
	 * @return
	 */
	@Override
	public Optional<Long> decrByImpl(String key, final long delta) {
		return incrBy(key, -delta);
	}

	// -------------------hash---------------------
	/**
	 * 获得map的值
	 * 
	 * @param key
	 *            Object
	 * @param field
	 *            String
	 * @return the value associated with field, or nil when field is not present
	 *         in the hash or key does not exist.
	 */
	@Override
	public <T> Optional<T> hgetImpl(String key, Object field) {
		if (!Optional.fromNullable(key).isPresent()) {
			return Optional.absent();
		}
		if (!Optional.fromNullable(field).isPresent()) {
			return Optional.absent();
		}
		return (Optional<T>) getOptional(template.opsForHash().get(key, field));
	}
	/**
	 * 获得map的值
	 * 
	 * @param key
	 * @param field
	 * @param clz
	 *            the value reference T
	 * @return the value associated with field, or nil when field is not present
	 *         in the hash or key does not exist.
	 */
	@Override
	public <T> Optional<T> hgetImpl(String key, Object field, Class<T> clz) {
		if (!Optional.fromNullable(key).isPresent()) {
			return Optional.absent();
		}
		if (!Optional.fromNullable(field).isPresent()) {
			return Optional.absent();
		}
		return getOptional(template.opsForHash().get(key, field, clz));
	}
	/**
	 * 获得map的值，list形式
	 * 
	 * @param key
	 * @param field
	 * @param clz
	 * @return
	 */
	@Override
	public <E> Optional<List<E>> hgetForListImpl(String key, Object field, Class<E> clz) {
		if (!Optional.fromNullable(key).isPresent()) {
			return Optional.absent();
		}
		if (!Optional.fromNullable(field).isPresent()) {
			return Optional.absent();
		}
		template.setConvertType(new TypeReference<List<E>>(clz) {
		});
		HashOperations<String, Object, List<E>> hashOps = template.opsForHash();
		return getOptional(hashOps.get(key, field));
	}
	/**
	 * 设置map的值
	 * 
	 * @param key
	 * @param field
	 * @param value
	 */
	@Override
	public void hsetImpl(String key, Object field, String value) {
		if (!Optional.fromNullable(key).isPresent()) {
			return;
		}
		if (!Optional.fromNullable(field).isPresent()) {
			return;
		}
		if (!Optional.fromNullable(value).isPresent()) {
			return;
		}
		HashOperations<String, Object, Object> hashOps = template.opsForHash();
		hashOps.put(key, field, value);
	}
	/**
	 * 设置map的值
	 * 
	 * @param key
	 * @param field
	 * @param value
	 */
	@Override
	public void hsetImpl(String key, Object field, Object value) {
		if (!Optional.fromNullable(key).isPresent()) {
			return;
		}
		if (!Optional.fromNullable(field).isPresent()) {
			return;
		}
		if (!Optional.fromNullable(value).isPresent()) {
			return;
		}
		template.opsForHash().put(key, field, value);
	}
	/**
	 * 设置map的多个值
	 * @param key
	 * @param hashMap
	 */
	@Override
	public void hmsetImpl(String key, Map<Object, Object> hashMap) {
		if (!Optional.fromNullable(key).isPresent()) {
			return;
		}
		if (!Optional.fromNullable(hashMap).isPresent()) {
			return;
		}
		Map<String, String> put_map = Maps.newHashMapWithExpectedSize(hashMap.size());
		template.opsForHash().putAll(key, put_map);
	}
	/**
	 *删除map的值
	 * @param key
	 * @param field
	 * @return
	 */
	@Override
	public Optional<Long> hdelImpl(String key, String field) {
		if (!Optional.fromNullable(key).isPresent()) {
			return Optional.absent();
		}
		if (!Optional.fromNullable(field).isPresent()) {
			return Optional.absent();
		}
		return getOptional(template.opsForHash().delete(key, field));
	}
	/**
	 * 设置过期时间
	 * @param key
	 *            String
	 * @param seconds
	 *            timeout
	 * @return
	 */
	@Override
	public Optional<Boolean> expireImpl(String key, long seconds) {
		return expire(key, seconds, TimeUnit.SECONDS);
	}
	/**
	 * 设置生存时长
	 * 
	 * @param key
	 *            String
	 * @param timeout
	 *            timeout
	 * @param unit
	 *            time unit
	 * @return
	 */
	@Override
	public Optional<Boolean> expireImpl(String key, long timeout, TimeUnit unit) {
		if (!Optional.fromNullable(key).isPresent()) {
			return Optional.of(false);
		}
		if (!Optional.fromNullable(timeout).isPresent()) {
			return Optional.of(false);
		}
		return getOptional(template.expire(key, timeout, unit));
	}
	/**
	 * 设置过期时间
	 * @param key
	 * @param date
	 * @return
	 */
	@Override
	public Optional<Boolean> expireAtImpl(String key, Date date) {
		if (!Optional.fromNullable(key).isPresent()) {
			return Optional.of(false);
		}
		if (!Optional.fromNullable(date).isPresent()) {
			return Optional.of(false);
		}
		return getOptional(template.expireAt(key, date));
	}

	/**
	 * 删除指定的键
	 * 
	 * @param key
	 */
	@Override
	public void delImpl(String key) {
		if (!Optional.fromNullable(key).isPresent()) {
			return;
		}
		template.delete(key);
	}

	/**
	 * 删除指定的多个键
	 * 
	 * @param keys
	 */
	@Override
	public void delImpl(String... keys) {
		List<String> list = Lists.newArrayList();
		for (String string : keys) {
			if (Optional.fromNullable(string).isPresent()) {
				list.add(string);
			}
		}
		if (list.size() == 0) {
			return;
		}
		template.delete(list);
	}

	private <T> Optional<T> getOptional(T obj) {
		if (!Optional.fromNullable(obj).isPresent()) {
			return Optional.absent();
		}
		return Optional.fromNullable(obj);
	}
	/**
	 * 获得RedisTemplate
	 * @return
	 */
	@Override
	public RedisTemplate<String, Object> getTemplate() {
		return template;
	}
	/**
	 * 获得FastJsonRedisTemplate
	 * @return
	 */
	@Override
	public FastJsonRedisTemplate<String, Object> getFastJsonRedisTemplate() {
		return template;
	}

	/**
	 *   忽略redis的异常，如果是，则执行redis下一条命令错误后，将不会抛出异常，但会打印日志 注意，redis命令执行后，会自动失效
	 */
	@Override
	public void ignoreRedisException() {
		template.ignoreRedisException();
	}
	/**
	 * 是否存在该键值
	 * @param key
	 * @return
	 */
	@Override
	public Optional<Boolean> hasKeyImpl(String key){
		return getOptional(template.hasKey(key));
	}
}